#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <sqlite3.h>
#include "netdrive.h"
#include "cJSON.h"

//#define QUOTAALERT
#define DBNAME "cloudBackup"
//#define RENAMECLOUDFOLDER
#define EMAILNOTIFY
#ifdef EMAILNOTIFY
char emailErr[128];
#endif
//#define PRINTNODES
char USBPath[16];
sqlite3 *db;
//int tmpID=100;
long backupSize=0, finishSize=0;
extern struct interface amazon_interface;
static struct interface *drive_interface;

char elname[128];
char elid[32];
char elpid[32];
char *elpth;
extern notify_flag;
extern BackupFlag;

struct nodes *backupNodes, *deleteNodes, *updateNodes, *tmpBackupNodes, *tmpChildrenNodes, *tmpDeleteNodes, *tmpUpdateNodes;

struct nodes *isExist(char *name, struct nodes *ns);
int readDirFromDB(char *id, struct nodes *ns);
int getBackupDir(char *usb, char *name, char *dir);
int getCloudID(sqlite3 *db, char *name, char *dir, char *id);
int createTables(sqlite3 *db);
int dropTables(sqlite3 *db);
int printfErr(sqlite3 *db, char *err_msg);
int callback_getDecendant(void *NotUsed, int argc, char **argv, char **azColName);
int scanDir(char *dir, char *folderID);
int notify_scan(char *dir, char *folderID);
int saveIntoBackup(char *name, char *pathname, int kind, char *parentid, struct stat sb);
int uploadFile(struct nodeElement element);
int uploadFolder(struct nodeElement element);
int addToTable(struct nodeElement element);
int backupToCloud(struct nodes *ns);
int getDelete(struct nodes *ns, char *dir);
int deleteInCloud(struct nodes *ns);
int notify_delete(struct nodes *ns);
int deleteInDB(char *delID);
int updateInCloud(struct nodes *ns);
int notify_update(struct nodes *ns);
int saveIntoUpdate(struct nodes *ns, char *pathname, long size, char *parentid);
int intialStructure();
int updateDB(struct nodeElement element);
int getFolderSize(char *dir);
int copyDB(char *from, char *to);
int setBackupStatus(char *status, char *process, char *errMsg);
cJSON *getJSONcode(char *filename);
char *findItemInArray(char *file, char *arrayName, char *srcName, char *srcValue, char *desName, char *kind);
int refresh_status();
int dropErrorTables(sqlite3 *db);
int addToError(struct nodeElement elm, int code);
int getErrMsg(code, errMsg);
int readError(sqlite3 *db);
int callback_readError(void *dataArray, int argc, char **argv, char **azColName);
int writeBackupSize();

int backup(int argc, char *argv[])
{
	char backupFolder[128], backupDir[256], backupCloudID[32];
	char usbDBName[64], localDBName[32];
	time_t now;
    int nkind,naction;
    char nname[128],npath[256];
	//setBackupStatus("1", NULL, "");
    if(notify_flag==1)
    {
        system("/usr/sbin/file_notify -r /tmp/even_w");
        char *tmp_name=config_get("notify_name");
        strncpy(nname,tmp_name,128);
        char *tmp_path=config_get("notify_path");
        strncpy(npath,tmp_path,256);
        char *tmp_kind=config_get("notify_kind");
        nkind=atoi(tmp_kind);
        char *tmp_action=config_get("notify_action");
        naction=atoi(tmp_action);
        fprintf(stderr,"path:%s,name:%s,kind:%d,action:%d\n",npath,nname,nkind,naction);
        fprintf(stderr,"start loop to check\n");
    }

	getBackupDir(USBPath, backupFolder, backupDir);

	//open database 
	snprintf(usbDBName, 64, "%s/.%s", USBPath, DBNAME);
	snprintf(localDBName, 64, "/tmp/drive/%s", DBNAME);
	int rc=sqlite3_open(usbDBName, &db);
	if (rc != SQLITE_OK) printfErr(db, sqlite3_errmsg(db));
	
	//create Nodes and NodeRelation tables and nodeid Index
	createTables(db);

	//get cloud id
	getCloudID(db, backupFolder, backupDir, backupCloudID);
//	fprintf(stderr, "Backup Folder:%s(cloud id is:%s)\n", backupDir, backupCloudID);
	
	//copy DB to local
	sqlite3_close(db);
	copyDB(usbDBName, localDBName);
	rc = sqlite3_open(localDBName, &db);
	if (rc != SQLITE_OK) printfErr(db, sqlite3_errmsg(db));

	//initial	
	intialStructure();
    if(notify_flag==1)
    {
        LOG("[Notify Cloud Backup]Scan dir:%s (id:%s) #timestamp:%ld", backupDir, backupCloudID, time(&now));
        notify_scan(backupDir, backupCloudID);
        LOG("[Notify Cloud Backup]Finish Scan %s. Backup size: %ld #timestamp:%ld", backupDir, backupSize, time(&now));
    }
    else
    {
        //scan dir
        LOG("[Cloud Backup]Scan dir:%s (id:%s) #timestamp:%ld", backupDir, backupCloudID, time(&now));
        scanDir(backupDir, backupCloudID);
        LOG("[Cloud Backup]Finish Scan %s. Backup size: %ld #timestamp:%ld", backupDir, backupSize, time(&now));
    }
	
	setBackupStatus(NULL, "0", "");

	//copy DB to USB 
	sqlite3_close(db);
	copyDB(localDBName, usbDBName);
	rc = sqlite3_open(usbDBName, &db);
	if (rc != SQLITE_OK) printfErr(db, sqlite3_errmsg(db));

	//calculate cloud quota
	if(calculateQuota() == -1)
	{
		setBackupStatus("-2", NULL, "Failed to Get Quota, please check your network and try again");
		exit(EXIT_FAILURE);
	}
	
	writeBackupSize();

	//bakcup to Cloud
    if(notify_flag==1)
    {
        LOG("action is %d",naction);
        LOG("naction is 0-create,1-delete,other-modify");
        if(naction==0) //create file or folder
        {
            LOG("[NOtify Cloud Backup]Upload Folders or Files that are Added #timestamp:%ld", time(&now));
            backupToCloud(backupNodes);	
        }
        if(naction==1)
        {
            LOG("[Notify Cloud Backup]Delete Folders or Files that are Removed #timestamp:%ld***", time(&now));
            notify_delete(deleteNodes);
        }
        if(naction !=0 && naction !=1)
        {
            LOG("[Notify Cloud Backup]Update Files that are Modified #timestamp:%ld***", time(&now));
            notify_update(updateNodes);

        }
        LOG("[Notify Cloud Backup]Finish Backup #timestamp: %ld", time(&now));
    }
    else
    {
	LOG("[Cloud Backup]Upload Folders or Files that are Added #timestamp:%ld", time(&now));
	backupToCloud(backupNodes);	
	LOG("[Cloud Backup]Delete Folders or Files that are Removed #timestamp:%ld***", time(&now));
	deleteInCloud(deleteNodes);
	LOG("[Cloud Backup]Update Files that are Modified #timestamp:%ld***", time(&now));
	updateInCloud(updateNodes);
	LOG("[Cloud Backup]Finish Backup #timestamp: %ld", time(&now));
    }

	setBackupStatus(NULL, "100", "");
	
	if (readError(db))
		setBackupStatus("-1", "0", "");
	else 
	 	setBackupStatus("0", "0", "");
	
	dropErrorTables(db);
	
	sqlite3_close(db);
    if(notify_flag !=1)
        system("echo 1 > /tmp/bk_status");
    if(notify_flag ==1)
        system("echo 1 > /tmp/notify_status");
    return 0;
}

int writeBackupSize()
{
	FILE *fd;
	fd = fopen("/tmp/drive/backupSize", "wb");
	fprintf(fd, "%ld", backupSize);
	fclose(fd);
	return 0;
}

int calculateQuota(){
	int code = 0;
	double quota, avail, used, per;
	char *plan;

	LOG("[Cloud Backup]Wait to Get Cloud Quota...");
	code = drive_interface->get_quota();
	if(code != 200) 
		return -1;

	cJSON *root, *dataArray, *quotaItem, *availItem, *planItem;
	if(!(root=getJSONcode("/tmp/drive/output"))){
		LOG("fail to get JSON code of Quota");
		return -1;
	}

	if(root){
		if(dataArray=cJSON_GetObjectItem(root, "plans"))
			if(planItem=cJSON_GetArrayItem(dataArray,0))
				plan=planItem->valuestring;

		if(dataArray == NULL || strcmp(plan, "CDSPUS0000")) //if plan is not unlimited-everything
		{ 
			if((quotaItem=cJSON_GetObjectItem(root, "quota")) && (availItem=cJSON_GetObjectItem(root, "available")))
			{
				avail=availItem->valuedouble;
				LOG("Avail %.2f", avail);
				if ((double)backupSize >= avail){
					system("/etc/email/send_email_alert amazon_cloud_backup drive_storage_alert");
					setBackupStatus("-2", NULL, "Cloud Drive has no enough space");
					syslog(LOG_INFO,"[Cloud Backup]Your cloud Drive has no enough space,");
					exit(EXIT_FAILURE);
				}
			}
		}
	}else{
		return -1;
		LOG("fail to parse json, return");
	}
	
	return 0;
}

int copyDB(char *from, char *to)
{
	char cmd[128];
	memset(cmd, 0, 128);
	sprintf(cmd, "cp %s %s", from, to);
	system(cmd);
	return 0;
}

int intialStructure()
{
	updateNodes = (struct nodes *)malloc(sizeof(struct nodes));	
	tmpUpdateNodes = updateNodes;
	tmpUpdateNodes->next=NULL; 
	deleteNodes = (struct nodes *)malloc(sizeof(struct nodes));	
	tmpDeleteNodes = deleteNodes;
	tmpDeleteNodes->next=NULL;
	backupNodes = (struct nodes *)malloc(sizeof(struct nodes));	
	tmpBackupNodes = backupNodes;
	tmpBackupNodes->next=NULL;
	return 0;
}

int updateDB(struct nodeElement element)
{
	char *err_msg=0;
	char *sql = sqlite3_mprintf("Update Nodes SET mtime = %ld WHERE id = '%q';", element.mtime, element.id);		
	
	int rc = sqlite3_exec(db, sql, callback_getDecendant, 0, &err_msg);
	sqlite3_free(sql);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);
	
	return 1;
}

int notify_update(struct nodes *ns)
{
    struct nodes *tmp;
    int errFlg=0;
    drive_interface = &amazon_interface;
    tmp=ns;
    if(strcmp(elname," ")==0 && (strcmp(elid," ")==0))
    {
        LOG("elname or elid is null");
        return 1;
    }
    int kind=atoi(config_get("notify_kind"));
//    LOG("elname=%s,elid=%s,elpid=%s,elpth=%s",elname,elid,elpid,elpth);
    strncpy(tmp->element.name,elname,128);
    strncpy(tmp->element.id,elid,32);
    strncpy(tmp->element.parentid,elpid,32);
    tmp->element.pathname=elpth;
    tmp->element.kind=kind;
    //	struct nodeElement tmpElement;
    LOG("[Cloud Notify Backup]Update %s (id %s parentid:%s pathname:%s and kind:%d)", tmp->element.name, 
            tmp->element.id,tmp->element.parentid,tmp->element.pathname,tmp->element.kind);
    int retFl=0; 
    char msg[128];
    int code = drive_interface->overwrite(tmp->element.id, tmp->element.pathname, msg, &retFl);
    if (code == 200) {
        updateDB(tmp->element);
    }else if(code == 400 && retFl){
        deleteInDB(tmp->element.id);
        code = drive_interface->upload_file(tmp->element.name, tmp->element.pathname, tmp->element.parentid, tmp->element.id, &retFl);
        if(code == 201)
            addToTable(tmp->element);
        else if (code == 400 && retFl)
            deleteInDB(tmp->element.parentid);
        else
            errFlg=1;
    }else
        errFlg=1;	

    if(errFlg)
    {
        LOG("[Cloud Backup]Failed to update %s (id %s)", tmp->element.pathname, tmp->element.id);
        addToError(tmp->element, code); //name, pathname, kind, size, stime, error	
#ifdef EMAILNOTIFY
        memset(emailErr, 0, 128);
        sprintf(emailErr, "/etc/email/send_email_alert amazon_cloud_backup backup_error update %s", tmp->element.pathname);
        system(emailErr);
#endif
    }
    //		LOG("[Cloud Backup Test]upload size:%ld", tmp->element.size);
    finishSize += tmp->element.size;
    finishSize += 1;
    refresh_status();
    return 0;
}

int updateInCloud(struct nodes *ns)
{
	struct nodes *tmp;
	int errFlg=0;
	drive_interface = &amazon_interface;
	for (tmp=ns->next; tmp; tmp=tmp->next)
	{
	//	struct nodeElement tmpElement;
		LOG("[Cloud Backup]Update %s (id %s)", tmp->element.name, tmp->element.id);
		int retFl=0;
		char msg[128];
		int code = drive_interface->overwrite(tmp->element.id, tmp->element.pathname, msg, &retFl);
		if (code == 200) {
			updateDB(tmp->element);
		}else if(code == 400 && retFl){
			deleteInDB(tmp->element.id);
			code = drive_interface->upload_file(tmp->element.name, tmp->element.pathname, tmp->element.parentid, tmp->element.id, &retFl);
			if(code == 201)
				addToTable(tmp->element);
			else if (code == 400 && retFl)
				deleteInDB(tmp->element.parentid);
			else
				errFlg=1;
		}else
			errFlg=1;	
		
		if(errFlg)
		{
			LOG("[Cloud Backup]Failed to update %s (id %s)", tmp->element.pathname, tmp->element.id);
			addToError(tmp->element, code); //name, pathname, kind, size, stime, error	
			#ifdef EMAILNOTIFY
				memset(emailErr, 0, 128);
				sprintf(emailErr, "/etc/email/send_email_alert amazon_cloud_backup backup_error update %s", tmp->element.pathname);
				system(emailErr);
			#endif
		}
//		LOG("[Cloud Backup Test]upload size:%ld", tmp->element.size);
		finishSize += tmp->element.size;
		finishSize += 359;
		refresh_status();
	}
	return 0;
}

int notify_delete(struct nodes *ns)
{
	struct nodes *tmp;
	drive_interface = &amazon_interface;
    tmp=ns;
    if(strcmp(elname," ")==0 && (strcmp(elid," ")==0))
    {
        LOG("elname or elid is null");
        return 1;
    }
    LOG("[ Notify Cloud Backup]Delete name:%s id:%s parentid:%s", elname, elid,elpid);
    int code = drive_interface->delete(elid);
    if (code == 200 || code == 409 || code == 404) {
        //delete from DB
        deleteInDB(elid);	
    }else{
        LOG("[Notify Cloud Backup]Failed to delete name:%s id:%s", elname,elid);
        strncpy(tmp->element.name,elname,128);
        strncpy(tmp->element.id,elid,32);
        strncpy(tmp->element.parentid,elpid,32);
        addToError(tmp->element, code); //name, pathname, kind, size, stime, error	
#ifdef EMAILNOTIFY
        memset(emailErr, 0, 128);
        sprintf(emailErr, "/etc/email/send_email_alert amazon_cloud_backup backup_error delete %s", tmp->element.pathname);
        system(emailErr);
#endif
    }
    finishSize += 1;
    refresh_status();
}

int deleteInCloud(struct nodes *ns)
{
	struct nodes *tmp;
	drive_interface = &amazon_interface;
	for (tmp=ns->next; tmp; tmp=tmp->next)
	{
		//delete
		LOG("[Cloud Backup]Delete name:%s id:%s", tmp->element.name, tmp->element.id);
		int code = drive_interface->delete(tmp->element.id);
		if (code == 200 || code == 409 || code == 404) {
			//delete from DB
			deleteInDB(tmp->element.id);	
		}else{
			LOG("[Cloud Backup]Failed to delete name:%s id:%s", tmp->element.name, tmp->element.id);
			addToError(tmp->element, code); //name, pathname, kind, size, stime, error	
			#ifdef EMAILNOTIFY
				memset(emailErr, 0, 128);
				sprintf(emailErr, "/etc/email/send_email_alert amazon_cloud_backup backup_error delete %s", tmp->element.pathname);
				system(emailErr);
			#endif
		}
		finishSize += 1;
		refresh_status();
	}
	return 0;
}

int deleteInDB(char *delID)
{
	char *err_msg=0;
	char *sql = sqlite3_mprintf("Delete FROM Nodes WHERE id in (Select descendant FROM NodeRelation WHERE ancestor='%q');"
		"Delete FROM NodeRelation WHERE descendant in (Select descendant from NodeRelation WHERE ancestor='%q')", delID, delID);		
	int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
	sqlite3_free(sql);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);
	return 0;
}	

int checkFolderName(char *fname)
{
	char tmp[128];
	int i, j;
	strcpy(tmp, fname);
	memset(fname, 0, 128);
	for(i=0, j=0; tmp[i]!='\0' && j < 128;i++, j++){
		if(tmp[i] != '%')
			fname[j] = tmp[i];
		else{
			fname[j++] = '%';	
			fname[j] = tmp[i];
		}
	}
	if (j == 128)
		fname[--j] = '\0';
	else
		fname[j] = '\0';

	fprintf(stderr, "folder name: %s\n", fname);
	return 0;
}

int getBackupDir(char *usbPath, char *folder, char *pathname)
{
	memset(usbPath, 0, 16);
	memset(folder, 0, 128);
	
	strcpy(usbPath, config_get("usb_path"));
	if( !*usbPath ) {
		setBackupStatus("-2", NULL, "No hard disk is chosen");
		exit(EXIT_FAILURE);
	}else if (access(usbPath, F_OK | R_OK | W_OK)){
		if (errno == EROFS) 
			setBackupStatus("-2", NULL, "Your hard disk is Read-only");
		else	
			setBackupStatus("-2", NULL, "Your hard disk is not accessible");
		exit(EXIT_FAILURE);
	}

	strcpy(folder, config_get("sync_local_folder"));	
	//checkFolderName(folder);
	if (!*folder) {
		setBackupStatus("-2", NULL, "No Backup Folder is Chosen");
	    exit(EXIT_FAILURE);
	}

	sprintf(pathname, "%s/%s", usbPath, folder);
	LOG("pathname:%s\n", pathname);
	if (access(pathname, F_OK)) {
		LOG("Invalid folder string err %d: %s", errno, strerror(errno));
	    config_set("drive_folder_invalid", "1");
		config_commit();
		setBackupStatus("-2", NULL, "Invalid Selected Folder");
		exit(EXIT_FAILURE);
	 }
	LOG("valid pathname\n");
	return 0;
}

int getCloudID(sqlite3 *db, char *name, char *pathname, char *id)
{
	char jsonFile[256];
	char *folderID, *cloudName;
	char rootID[32], configID[32];
	int code=0;

	drive_interface = &amazon_interface;
	
	//get rootid	
	memset(rootID, 0, 32);
	strcpy(rootID, config_get("drive_rootID"));	
	if (!*rootID){
		LOG("[Cloud Backup]Wait to Get Cloud Root ID");
		code = drive_interface->get_rootID();
		if(code != 200) {
			setBackupStatus("-2", NULL, "Failed to get root id, please check your network and try again");
			exit(EXIT_FAILURE);
		}else{
			memset(rootID, 0, 32);
			strcpy(rootID, config_get("drive_rootID"));	
		}
	}
	//list children	
	code = drive_interface->list_children(rootID);
	if(code != 200) {
		setBackupStatus("-2", NULL, "Failed to list children, please check your network and try again");
		exit(EXIT_FAILURE);
	}
	sprintf(jsonFile, "/tmp/drive/children_%s", rootID);
	
	memset(configID, 0, 32);
	strcpy(configID, config_get("syncup_folder_id"));	
	if (*configID) {
		if (cloudName = findItemInArray(jsonFile, "data", "id", configID, "name", "FOLDER"))
		{
			LOG("[Could Backup]Get Folder %s's Cloud Name: %s", name, cloudName);
			strcpy(id, configID);
			LOG("[Could Backup]Get Folder %s's Cloud ID: %s", name, id);
			return 1;
		}else {
			config_set("syncup_folder_id", "");
			config_commit();
			dropTables(db);
			createTables(db);
		}
	}
		
	LOG("[Could Backup]Waiting to Create Folder %s in Cloud", name);
	int retFl=0;
	code = drive_interface->create_folder(name, rootID, id, &retFl);
	
	if (code == 409){ 
		if(!strcmp(config_get("backup_cfl"), "1")) //rename
		{
			char *re_name=(char *)malloc(128 * sizeof(char));
			snprintf(re_name, 128, "%s-CloudBackup", name);
			code = drive_interface->rename(id, re_name);
			while (code == 409 && strlen(re_name) < 120){
				strncat(re_name, "-CloudBackup", 128 - strlen(re_name));
				code = drive_interface->rename(id, re_name);
			}
			free(re_name);
		}else{
			code = drive_interface->delete(id);
			if (code != 200){
				LOG("[Cloud Backup Fail]Failed to delete conflict folder. Exit!", name);
				setBackupStatus("-2", NULL, "Fail to delete conflict folder");
				exit(EXIT_FAILURE);
			}
		}
		code = drive_interface->create_folder(name, rootID, id, &retFl);
	}
	else if (code != 201) {
		LOG("[Cloud Backup Fail]Create Folder %s to Cloud Failed. Exit!", name);
		setBackupStatus("-2", NULL, "Fail to create Backup folder");
		exit(EXIT_FAILURE);
	}
	
	LOG("[Cloud Backup]Get Folder %s's Cloud ID: %s", name, id);
	config_set("syncup_folder_id", id);
	config_commit();
	
	//create and get id
	struct stat sb;
	char *err_msg=0;

	if(lstat(pathname, &sb)){
		LOG("[Cloud Bckup Error]failed to lstat %s, err: %s", pathname, strerror(errno));
		setBackupStatus("-2", NULL, "Lstat Failure");
		exit(EXIT_FAILURE);
	}

	char *sql = sqlite3_mprintf("Insert Into Nodes VALUES('%q', '%q', %d, 'FOLDER');"
				"Insert Into NodeRelation VALUES('%q', '%q', 0);", id, name, sb.st_size, id, id);		
	
	int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
	sqlite3_free(sql);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);
	return 0;
}

int createTables(sqlite3 *db)
{
	char *err_msg=0;
	char *sql = "CREATE TABLE IF NOT EXISTS Nodes(id TEXT PRIMARY KEY, name TEXT, mtime REAL, kind INTEGER);"
		    "CREATE TABLE IF NOT EXISTS NodeRelation(ancestor TEXT, descendant TEXT, depth INTEGER);"
		    "CREATE TABLE IF NOT EXISTS error(name TEXT, pathname TEXT, kind TEXT, size REAL, stime REAL, errMsg TEXT);"
		    "CREATE INDEX IF NOT EXISTS nodeid ON Nodes(id);"	
		    "CREATE INDEX IF NOT EXISTS childid ON NodeRelation(descendant);";	
	int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);
	return 0;
}

int dropErrorTables(sqlite3 *db)
{
	char *err_msg=0;
	char *sql = "DROP TABLE IF EXISTS error;";
	int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);
	return 0;
}

int dropTables(sqlite3 *db)
{
	char *err_msg=0;
	char *sql = "DROP INDEX IF EXISTS nodeid;"	
		    "DROP INDEX IF EXISTS childid;"	
			"DROP TABLE IF EXISTS Nodes;"
		    "DROP TABLE IF EXISTS NodeRelation;";
	int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);
	return 0;
}

int printfErr(sqlite3 *db, char *err_msg)
{
	LOG("[Cloud Backup Error]SQL error: %s", err_msg);
	sqlite3_free(err_msg);
	sqlite3_close(db);
	if(BackupFlag){
		setBackupStatus("-2", NULL, err_msg);
		exit(EXIT_FAILURE);
	}
	return 0;
}

int notify_scan(char *dir, char *folderID)
{
	DIR *dp;
	struct dirent *dirp;
	char *err_msg=0;
    int sresult;
	struct nodes *childrenNodes, *tmpNode, *lastNode;	
	
	LOG("[ NOtify Cloud Backup]Scan dir:%s (id: %s)", dir, folderID);

	childrenNodes = (struct nodes *)malloc(sizeof(struct nodes)); //should be freed later
	childrenNodes -> next = NULL;
	readDirFromDB(folderID, childrenNodes);
	printNodes(childrenNodes);

	if(!(dp = opendir(dir))) {
		LOG("[Notify Cloud Backup Error]CANNOT open dir %s", dir);
		return 0;
	}

	while(dirp = readdir(dp)) {
		struct stat sb;
		int len, kind;
		char *pathname;
		
		if(dirp->d_name[0] == '.')
			continue;
		
		len = strlen(dir) + strlen(dirp->d_name);
		pathname = (char *)malloc((len+2) * sizeof(char));
		sprintf(pathname, "%s/%s", dir, dirp->d_name);
		if(lstat(pathname, &sb)){
			LOG("[Notify Cloud Backup Error]CANNOT lstat %s", pathname);
			continue;
		}
		
		if (S_ISDIR(sb.st_mode))
			kind=BKFOLDER;
		else 
			kind=BKFILE;
			
		lastNode = isExist(dirp->d_name, childrenNodes);
		tmpNode = lastNode->next;
		if (tmpNode) //if exists
		{
            if(kind){
               sresult= notify_scan(pathname, tmpNode->element.id);
               if (sresult==1) return 1;
            }else{
                if((strcmp(dirp->d_name,config_get("notify_name"))==0)&& (strcmp(dir,config_get("notify_path"))==0) 
                        && (atoi(config_get("notify_action"))!=1)&& (atoi(config_get("notify_action"))!=0) ) //update
                {
                    LOG("[Notify] ************ will update node ****************");
                    LOG("[Notify Cloud update]name :%s ,pathname:%s,kind:%d,folderid:%s",dirp->d_name,pathname,kind,folderID);
                    tmpNode->element.mtime=sb.st_mtime;
                    saveIntoUpdate(tmpNode, pathname, sb.st_size, folderID);
                    backupSize += sb.st_size;
                    backupSize += 1;
                    strncpy(elname,dirp->d_name,128);
                    strncpy(elpid,folderID,32);
                    elpth=pathname;
                    free(tmpNode);
                    closedir(dp);
                    free(childrenNodes);
                    return 1;
                }
            }
            if((strcmp(elname,config_get("notify_name"))==0) && (atoi(config_get("notify_action"))==1) 
                    && (strcmp(dir,config_get("notify_path"))==0)) //delete
            {
                LOG("[Notify] ************ will delete node ****************");
                LOG("[Notify Cloud Delete]find elname: %s,elid:%s" ,elname,elid);
                strncpy(elpid,folderID,32);
                elpth=dir;
                closedir(dp);
                free(childrenNodes);
                free(tmpNode);
                return 1;
            }
			lastNode->next = tmpNode->next;
		}	
		else //if not exitst
		{
			LOG("[Notify Cloud Backup]%s not exists", dirp->d_name);
			saveIntoBackup(dirp->d_name, pathname, kind, folderID, sb);
			if(kind == BKFILE){
				backupSize += sb.st_size;
				backupSize += 1;
			}
			else{ 
				getFolderSize(pathname);
				backupSize += 1;
			}
            if((strcmp(dirp->d_name,config_get("notify_name"))==0) &&
                    (atoi(config_get("notify_action"))==0) && (strcmp(dir,config_get("notify_path"))==0)) //create
            {
                LOG("[Notify] ************ will create node ****************");
                LOG("[Notify Cloud Create]name :%s ,pathname:%s,kind:%d,folderid:%s",dirp->d_name,pathname,kind,folderID);
                strncpy(elname,dirp->d_name,128);
                strncpy(elpid,folderID,32);
                elpth=pathname;
                free(tmpNode);
                closedir(dp);
                free(childrenNodes);
                return 1;
            }
        }
		free(tmpNode);
	}
	closedir(dp);
	free(childrenNodes);
	return 0;
}

int scanDir(char *dir, char *folderID)
{
	DIR *dp;
	struct dirent *dirp;
	char *err_msg=0;
	struct nodes *childrenNodes, *tmpNode, *lastNode;	
	
	LOG("[Cloud Backup]Scan dir:%s (id: %s)", dir, folderID);

	childrenNodes = (struct nodes *)malloc(sizeof(struct nodes)); //should be freed later
	childrenNodes -> next = NULL;
	readDirFromDB(folderID, childrenNodes);

#ifdef PRINTNODES 
	printNodes(childrenNodes);
#endif

	if(!(dp = opendir(dir))) {
		LOG("[Cloud Backup Error]CANNOT open dir %s", dir);
		return 0;
	}

	while(dirp = readdir(dp)) {
		struct stat sb;
		int len, kind;
		char *pathname;
		
		if(dirp->d_name[0] == '.')
			continue;
		
		len = strlen(dir) + strlen(dirp->d_name);
		pathname = (char *)malloc((len+2) * sizeof(char));
		sprintf(pathname, "%s/%s", dir, dirp->d_name);	
		if(lstat(pathname, &sb)){
			LOG("[Cloud Backup Error]CANNOT lstat %s", pathname);
			continue;
		}
		
		if (S_ISDIR(sb.st_mode))
			kind=BKFOLDER;
		else 
			kind=BKFILE;
			
		lastNode = isExist(dirp->d_name, childrenNodes);
		tmpNode = lastNode->next;
		if (tmpNode) //if exists
		{
			fprintf(stderr, "%s exists\n", tmpNode->element.id);
			if(kind){
				scanDir(pathname, tmpNode->element.id);
			}else{
				if(sb.st_mtime != tmpNode->element.mtime){
					LOG("[Cloud Backup]%s has been modified", dirp->d_name);
					tmpNode->element.mtime=sb.st_mtime;
					saveIntoUpdate(tmpNode, pathname, sb.st_size, folderID);
					backupSize += sb.st_size;
					backupSize += 359;
//					LOG("[Cloud Backup Test]pathname:%s size:%ld", pathname, sb.st_size);
				}
			}
			lastNode->next = tmpNode->next;
		}	
		else //if not exitst
		{
			LOG("[Cloud Backup]%s not exists", dirp->d_name);
			saveIntoBackup(dirp->d_name, pathname, kind, folderID, sb);
			if(kind == BKFILE){
				backupSize += sb.st_size;
				backupSize += 359;
//				LOG("[Cloud Backup Test]pathname:%s size:%ld", pathname, sb.st_size);
			}
			else{ 
				getFolderSize(pathname);
				backupSize += 1;
			}
		}
		free(tmpNode);
//		free(lastNode);
	}
	closedir(dp);
	
	getDelete(childrenNodes, dir);
	free(childrenNodes);
	return 0;
}

int getFolderSize(char *dir)
{
	DIR *dp;
	struct dirent *dirp;

	if(!(dp = opendir(dir))) {
		fprintf(stderr, "CANNOt open dir %s\n", dir);
		return 0;
	}

	while(dirp = readdir(dp)) {
		struct stat sb;
		int len, kind;
		char *pathname;
		
		if(dirp->d_name[0] == '.')
			continue;

		len = strlen(dir) + strlen(dirp->d_name);
		pathname = (char *)malloc((len+2) * sizeof(char));
		sprintf(pathname, "%s/%s", dir, dirp->d_name);	
		if(lstat(pathname, &sb)){
			fprintf(stderr, "CANNOT lstat %s\n", pathname);
			continue;
		}
		
		if (S_ISDIR(sb.st_mode)){
			getFolderSize(pathname);
			backupSize += 1;	
		}
		else{ 
//			LOG("[Cloud Backup Test]pathname:%s size:%ld", pathname, sb.st_size);
			backupSize += sb.st_size;	
			backupSize += 359;	
		}
	}
	closedir(dp);
	return 0;
}

int getDelete(struct nodes *ns, char *dir)
{
	struct nodes *tp;
	for (tp = ns->next; tp; tp=tp->next)
	{
		int len=0;
		char *pathname;
		len = strlen(dir) + strlen(tp->element.name);
		pathname = (char *)malloc((len+2) * sizeof(char));
		sprintf(pathname, "%s/%s", dir, tp->element.name);	
		
		tmpDeleteNodes->next = (struct nodes *)malloc(sizeof(struct nodes));
		tmpDeleteNodes = tmpDeleteNodes->next;
		tmpDeleteNodes->element = tp->element;
		tmpDeleteNodes->element.pathname = pathname;
		tmpDeleteNodes->next = NULL;
		backupSize += 1;
		LOG("[Cloud Backup]%s has been Deleted in USB", tmpDeleteNodes->element.name);
	}
	return 0;
}

struct nodes *isExist(char *name, struct nodes *ns)
{
	struct nodes *tmp, *lastNode;
	for(lastNode=ns, tmp = ns->next; tmp; tmp = tmp->next)
	{
		if (!strcmp(tmp->element.name, name))
			return lastNode;
		lastNode = tmp;
	}
	return lastNode;	
}

int saveIntoUpdate(struct nodes *ns, char *pathname, long size, char *parentid)
{
	tmpUpdateNodes->next = (struct nodes *)malloc(sizeof(struct nodes));
	tmpUpdateNodes = tmpUpdateNodes->next;
	tmpUpdateNodes->element = ns->element;
	tmpUpdateNodes->element.size = size;
	tmpUpdateNodes->element.pathname = pathname;
	strncpy(tmpUpdateNodes->element.parentid, parentid, 32);
	tmpUpdateNodes->next = NULL;
	return 0;
}

int saveIntoBackup(char *name, char *pathname, int kind, char *parentid, struct stat sb)
{
	tmpBackupNodes->next = (struct nodes *)malloc(sizeof(struct nodes));
	tmpBackupNodes = tmpBackupNodes->next;
	strncpy(tmpBackupNodes->element.name, name, 128);
	tmpBackupNodes->element.pathname = pathname;
	tmpBackupNodes->element.kind = kind;
	tmpBackupNodes->element.mtime = sb.st_mtime;
	tmpBackupNodes->element.size = sb.st_size;
	strncpy(tmpBackupNodes->element.parentid, parentid, 32);
	strcpy(tmpBackupNodes->element.id, "0");
	tmpBackupNodes->next = NULL;
	return 0;
}

int backupToCloud(struct nodes *ns)
{
	struct nodes *tmp;
    if(notify_flag==1)
    {
        tmp=ns;
        char *tmp_kind=config_get("notify_kind");
        int nkind=atoi(tmp_kind);
        tmp->element.kind=nkind;
        strncpy(tmp->element.parentid,elpid,32);
        strncpy(tmp->element.name,elname,128);
        tmp->element.pathname=elpth;
        LOG("create name:%s,parentid:%s,pathname:%s,kind:%d",tmp->element.name,tmp->element.parentid,
                tmp->element.pathname,tmp->element.kind);
        if(nkind==1)
            uploadFolder(tmp->element);
        else
            uploadFile(tmp->element);
    }
    else
    {
        for (tmp = ns->next; tmp ;tmp=tmp->next)
        {
            if (tmp->element.kind) //folder 
                uploadFolder(tmp->element);
            else 
                uploadFile(tmp->element);
        }
    }
    return 0;
}

int checkCflFile(struct nodeElement element)
{
	char md5cld[33], md5loc[33], *cmdbuf, *md5file="/tmp/drive/md5", *newname;
	FILE *md5fd;
	//get cloud md5
	int code = drive_interface->get_metadata(element.id, AMAZON_GET_MD5, md5cld);
	if (code == 200)
		fprintf(stderr, "[Cloud Backup Test]md5 of cloud file %s is:%s\n", element.pathname, md5cld);
	else{
		LOG("[Cloud Backup TEST]Failed to get md5 of %s in cloud", element.pathname);
		return -1;
	}

	//get local md5
	int cmdlen=strlen(element.pathname) + 32;
	cmdbuf=(char *)malloc( cmdlen * sizeof(char));
	snprintf(cmdbuf, cmdlen, "md5sum %s > %s", element.pathname, md5file);	
	system(cmdbuf);
	free(cmdbuf);
	md5fd = fopen(md5file, "r");	
	memset(md5loc, 0, 33);
	fgets(md5loc, 33, md5fd);

	//get md5 fail	
	if(!*md5loc || !*md5cld)
		return -1;
	//compare them
	else if(strcmp(md5loc, md5cld)) //not the same file or fail to get md5, rename cloud
	{
		LOG("[Cloud Backup]Not the same file");	
		char *re_name=(char *)malloc(128 * sizeof(char));
		snprintf(re_name, 128,"%s-CloudBackup", element.name);
		code = drive_interface->rename(element.id, re_name);
		while(code == 409 && strlen(re_name) < 120){
			strncat(re_name, "-CloudBackup", 128 - strlen(re_name));
			code = drive_interface->rename(element.id, re_name);
		}
		free(re_name);
		if(code != 200)
			return -1;
		else{
			LOG("rename done");
			memset(element.id, 0, 32);
			int retFl=0;
			code = drive_interface->upload_file(element.name, element.pathname, element.parentid, element.id, &retFl);
			if(code == 201){
				if(retFl)
					return 1;
				else
					return -1;
			}else
				return -1;
		}
	}else{ //the same file
		LOG("[Cloud Backup]The same file");	
		return 0;
	}
}

int uploadFile(struct nodeElement element)
{
	int err_flag=0, code=0, retFl=0;
	
	drive_interface = &amazon_interface;
	LOG("[Cloud Backup]Upload File %s", element.pathname);
	code = drive_interface->upload_file(element.name, element.pathname, element.parentid, element.id, &retFl);
	if (code == 201) {
		if(retFl)
			addToTable(element);
		else
			err_flag=1;
	}else if(code == 400 && retFl){
		LOG("Restore: parentid:%s", element.parentid);
		code = drive_interface->restore(element.parentid);
		if(code == 200){
			memset(element.id, 0, 32);
			LOG("Upload again: name:%s, pathname:%s, parentid:%s", element.name, element.pathname, element.parentid);
			code = drive_interface->upload_file(element.name, element.pathname, element.parentid, element.id, &retFl);
			if(code != 201)
				err_flag=1;
			else
				addToTable(element);
		}else{
			err_flag=1;
			deleteInDB(element.parentid);
		}
	}else if (code == 409){
		int ret=0;
		ret=checkCflFile(element);
		if(ret == -1 )
			err_flag=1;
		else{ //the same
			deleteInDB(element.id);
			addToTable(element);
		}
	}else 
		err_flag = 1;
				
	if(err_flag)
	{
		LOG("[Cloud Backup Error]Failed to upload File %s", element.pathname);
		if(BackupFlag){
			addToError(element, code); //name, pathname, kind, size, stime, error	
			#ifdef EMAILNOTIFY
				memset(emailErr, 0, 128);
				sprintf(emailErr, "/etc/email/send_email_alert amazon_cloud_backup backup_error upload %s", element.pathname);
				system(emailErr);
			#endif
		}
	}

	finishSize += element.size;
	finishSize += 359;
	if(BackupFlag)
		refresh_status();
	return 0;
}

int uploadFolder(struct nodeElement element)
{
	DIR *dp;
	struct dirent *dirp;
	char *dir = element.pathname;
	//char folderid[32];

	drive_interface = &amazon_interface;
	//create folder	
	LOG("[Cloud Backup]Create Folder %s", dir);
	int retFl=0, errFlg=0;
	int code = drive_interface->create_folder(element.name, element.parentid, element.id, &retFl);
	if (code == 201) 
		if(retFl)
			addToTable(element);
		else{
			memset(element.id, 0, 32);	
			errFlg=1;
		}
	else if(code == 400 && retFl){
		code = drive_interface->restore(element.parentid);
		if(code == 200){
			code = drive_interface->create_folder(element.name, element.parentid, element.id, &retFl);
			if(code != 201)
				errFlg=1;
			else
				addToTable(element);
		}else{
			errFlg=1;
			deleteInDB(element.parentid);
		}
	}else if(code == 409){
		if(retFl)
			addToTable(element);
		else{
			memset(element.id, 0, 32);	
			deleteInDB(element.id);
			addToTable(element);
		}
	}
	else 
		errFlg=1;
	
	if(errFlg && BackupFlag)	
	{
		LOG("[Cloud Backup Error]Failed to create folder %s", element.pathname);
		if(BackupFlag){
			addToError(element, code); //name, pathname, kind, size, stime, error	
			#ifdef EMAILNOTIFY
			memset(emailErr, 0, 128);
			sprintf(emailErr, "/etc/email/send_email_alert amazon_cloud_backup backup_error create %s", dir);
			system(emailErr);
			#endif
		}
		errFlg=0;
		return 0;
	}
	
	finishSize += 1;
	if(BackupFlag)
		refresh_status();
	
	if(!(dp = opendir(dir))) {
		fprintf(stderr, "CANNOt open dir %s\n", dir);
		return 0;
	}

	while(dirp = readdir(dp)) {
		struct stat sb;
		int len, kind;
		char *pathname;
		struct nodeElement elm;
	
		if(dirp->d_name[0] == '.')
			continue;

		len = strlen(dir) + strlen(dirp->d_name);
		pathname = (char *)malloc((len+2) * sizeof(char));
		sprintf(pathname, "%s/%s", dir, dirp->d_name);	
		if(lstat(pathname, &sb)){
			fprintf(stderr, "CANNOT lstat %s\n", pathname);
			continue;
		}
		
		elm.mtime=sb.st_mtime;
		elm.size=sb.st_size;
		elm.pathname=pathname;
		strncpy(elm.name, dirp->d_name, 128);
		strncpy(elm.parentid, element.id, 32);
		
		if (S_ISDIR(sb.st_mode)){
			elm.kind=BKFOLDER;
			uploadFolder(elm);
		}else{ 
			elm.kind=BKFILE;
			//upload file
			LOG("[Cloud Backup]Upload File %s", pathname);
			int retFl=0; 
			int code = drive_interface->upload_file(dirp->d_name, pathname, element.id, elm.id, &retFl);
			if (code == 201) {
				if(retFl)
					addToTable(elm);
				else{
					memset(elm.id, 0, 32);
					errFlg=1;
				}
			}
			else if (code == 409){
				if(retFl){
					deleteInDB(elm.id);
					addToTable(elm);
				}else{
					memset(elm.id, 0, 32);
					errFlg=1;
				}
			}
			else 
				errFlg=1;
			
			if(errFlg && BackupFlag)
			{
				LOG("[Cloud Backup Error]Failed to upload File %s", pathname);
				addToError(elm, code); //name, pathname, kind, size, stime, error	
			#ifdef EMAILNOTIFY
				memset(emailErr, 0, 128);
				sprintf(emailErr, "/etc/email/send_email_alert amazon_cloud_backup backup_error upload %s", pathname);
				system(emailErr);
			#endif
				errFlg=0;
			}

//			LOG("[Cloud Backup Test]upload size:%ld", sb.st_size);
			finishSize += sb.st_size;
			finishSize += 359;
			
			if(BackupFlag)
				refresh_status();
		}	
	}
	closedir(dp);
	return 0;
}

int getErrMsg(code, errMsg)
{
	switch (code){
		case 400:
			strcpy(errMsg, "Bad Request");
			break;
		case 401:
			strcpy(errMsg, "Unauthorized");
			break;
		case 403:
			strcpy(errMsg, "Forbidden");
			break;
		case 404:
			strcpy(errMsg, "Not Found");
			break;
		case 405:
			strcpy(errMsg, "Method Not Allowed");
			break;
		case 411:
			strcpy(errMsg, "Length Required");
			break;
		case 412:
			strcpy(errMsg, "Precondition Failed");
			break;
		case 429:
			strcpy(errMsg, "Too Many Required");
			break;
		case 500:
			strcpy(errMsg, "Internal Server Error");
			break;
		case 503:
			strcpy(errMsg, "Server Unavailable");
			break;
		default:
			strcpy(errMsg, "Network Fail");
	}
	return 0;
}

int addToError(struct nodeElement elm, int code)
{
	char *err_msg=0;
	time_t now;
	char errMsg[128];
	char kd[8];
	
	getErrMsg(code, errMsg);
	if (elm.kind)
		strcpy(kd, "FOLDER");
	else
		strcpy(kd, "FILE");
	char *sql = sqlite3_mprintf("Insert Into error VALUES('%q', '%q', '%q', %ld, %ld, '%q');", elm.name, elm.pathname, kd, elm.size, time(&now), errMsg);		
	LOG("[Cloud Backup Test]sql: %s", sql);	
	//fprintf(stderr, "%s", sql);
	int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
	sqlite3_free(sql);
	if (rc != SQLITE_OK) {
		printfErr(db, err_msg);
		return 0;
	}
	
	return 1;	
}	

int addToTable(struct nodeElement elm)
{
	char *err_msg=0;
	
	char *sql = sqlite3_mprintf("Insert Into Nodes(id, name, mtime, kind) VALUES('%q', '%q', %ld, %d);"
		"Insert Into NodeRelation(ancestor, descendant, depth)\n"
		"Select n.ancestor, '%q', n.depth+1\n"
		"FROM NodeRelation n\n"
		"WHERE n.descendant = '%q'\n"
		"Union ALL\n"
		"Select '%q', '%q', 0;\n", elm.id, elm.name, elm.mtime, elm.kind, elm.id, elm.parentid, elm.id, elm.id);		
	//fprintf(stderr, "%s", sql);
	int rc = sqlite3_exec(db, sql, 0, 0, &err_msg);
	sqlite3_free(sql);
	if (rc != SQLITE_OK) {
		printfErr(db, err_msg);
		return 0;
	}
	
	return 1;	
}	

int readDirFromDB(char *id, struct nodes *ns)
{
	char *err_msg=0;
	char *sql = sqlite3_mprintf("Select id, name, kind, mtime FROM Nodes WHERE id in (Select descendant FROM NodeRelation WHERE ancestor = '%q' and depth =1);", id );		
	tmpChildrenNodes = ns;
	int rc = sqlite3_exec(db, sql, callback_getDecendant, 0, &err_msg);
	sqlite3_free(sql);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);
	
	return 1;
}

int callback_getDecendant(void *NotUsed, int argc, char **argv, char **azColName)
{
	NotUsed = 0;
	tmpChildrenNodes->next = (struct nodes *)malloc(sizeof(struct nodes));
	tmpChildrenNodes = tmpChildrenNodes->next;
	strncpy(tmpChildrenNodes->element.id, argv[0], 32);	
	strncpy(tmpChildrenNodes->element.name, argv[1], 128);
	tmpChildrenNodes->element.kind=atoi(argv[2]);
	tmpChildrenNodes->element.mtime=atol(argv[3]);
	strcpy(tmpChildrenNodes->element.parentid, "0");
	tmpChildrenNodes->element.pathname = NULL;
	tmpChildrenNodes->next = NULL;
//	fprintf(stderr, "id: %s name: %s, kind: %d, mtime: %ld\n", tdns->element.id, tdns->element.name, tdns->element.kind, tdns->element.mtime);
	return 0;
}

int setBackupStatus(char *status, char *process, char *errMsg)
{
	if (status) 
		config_set("amazon_sync", status);

	if (process){
		FILE *fd, *ufd;
		fd = fopen("/tmp/drive/finishSize", "wb");
		if(!strcmp(process, "0")){
			fprintf(fd, "0");
			ufd = fopen("/tmp/drive/uploadSize", "wb");
			fprintf(ufd, "0");
			fclose(ufd);
			ufd = fopen("/tmp/drive/backupSize", "wb");
			fprintf(ufd, "BEGIN");
			fclose(ufd);
		}
		else if(!strcmp(process, "100"))
			fprintf(fd, "FINISH");
		fclose(fd);
	}

	config_set("backup_error_other", errMsg);
	config_commit();

	if(*errMsg)
		LOG("[Cloud Backup Fail]%s", errMsg);
	return 0;
}

cJSON *getJSONcode(char *filename)
{
	FILE *tfp;
	cJSON *root;
	int i=0;
	char c,json_buf[65535];
	root=NULL;
	json_buf[0]='\0';
	if((tfp = fopen(filename, "r")) == NULL)
		return NULL;
	fseek(tfp, 0, SEEK_SET);
	while((c = fgetc(tfp)) !=EOF && i < sizeof(json_buf)-1)
		json_buf[i++] = c;
	
	json_buf[i] = '\0';
	fclose(tfp);
	root = cJSON_Parse(json_buf);
	return root;
}

char *findItemInArray(char *file, char *arrayName, char *srcName, char *srcValue, char *desName, char *kind)
{
	cJSON *root, *dataArray, *Item, *srcItem;
	int arraySize=0;
	int i=0;

	if(!(root=getJSONcode(file))){
		LOG("fail to get JSON code of %s", file);
		return NULL;
	}
	
	dataArray=cJSON_GetObjectItem(root, "data");
	arraySize=cJSON_GetArraySize(dataArray);
	
	for(i=0;i<arraySize;i++)
	{
		Item=cJSON_GetArrayItem(dataArray,i);	
		if(srcItem = cJSON_GetObjectItem(Item,srcName)){
			if(!strcmp(srcValue,srcItem->valuestring))
			{
				if(!strcmp(kind,cJSON_GetObjectItem(Item,"kind")->valuestring))
				{
					return cJSON_GetObjectItem(Item,desName)->valuestring;
				}
				else
					return NULL;
			}
		}
	}
	return NULL;
}
	
int refresh_status()
{
	FILE *fd;
	fd = fopen("/tmp/drive/uploadSize", "wb");
	fprintf(fd, "0");
	fclose(fd);
	
	fd = fopen("/tmp/drive/finishSize", "wb");
	fprintf(fd, "%ld", finishSize);
	fclose(fd);
	return 0; 
}

int readError(sqlite3 *db)
{
	cJSON *root, *dataArray; 
	char *err_msg=0;
	FILE *fp;
	char file[256];
	
	root=cJSON_CreateObject();
	cJSON_AddItemToObject(root, "data", dataArray=cJSON_CreateArray());

	char *sql = sqlite3_mprintf("Select * FROM error;");		
	int rc = sqlite3_exec(db, sql, callback_readError, dataArray, &err_msg);
	sqlite3_free(sql);
	if (rc != SQLITE_OK) 
		printfErr(db, err_msg);

	int arraySize=cJSON_GetArraySize(dataArray);
	cJSON_AddNumberToObject(root, "count", arraySize);
	char *out=cJSON_PrintUnformatted(root);
	sprintf(file, "%s/.amazon_Sync_errorMsg", USBPath);
	fprintf(stderr, "%s, usb:%s\n", file, USBPath);
	if(!(fp = fopen(file, "w"))){
		LOG("fail to open %s, error %s", file, strerror(errno));
		return 0;
	}
	fprintf(fp, "%s\n", out);
	fclose(fp);
	cJSON_Delete(root);
	free(out);
	return arraySize;
}

int callback_readError(void *dataArray, int argc, char **argv, char **azColName)
{
	cJSON *itemObject;	
	cJSON_AddItemToArray((cJSON *)dataArray, itemObject = cJSON_CreateObject());
	cJSON_AddStringToObject(itemObject, "name", argv[0]);
	cJSON_AddStringToObject(itemObject, "pathname", argv[1]);
	cJSON_AddStringToObject(itemObject, "kind", argv[2]);
	cJSON_AddStringToObject(itemObject, "size", argv[3]);
	cJSON_AddStringToObject(itemObject, "stime", argv[4]);
	cJSON_AddStringToObject(itemObject, "errMsg", argv[5]);
	return 0;
}

int printNodes(struct nodes *ns)
{
	struct nodes *tmp;
	for (tmp=ns->next; tmp; tmp=tmp->next)
    {
        if(notify_flag==1)
        {
            char *tmp_name=config_get("notify_name");
            char tp_name[128];
            strncpy(tp_name,tmp_name,128);
            if(strcmp(tmp->element.name,tp_name)==0 )
            {
                LOG("[***Cloud Notify Test***]name: %s, id: %s", tmp->element.name, tmp->element.id);
                strncpy(elname,tmp->element.name,128);
                strncpy(elid,tmp->element.id,32);
                //strncpy(elpid,tmp->element.parentid,32);
                break;    
            }
        }
        else
            LOG("[Cloud Backup Test]name: %s, id: %s", tmp->element.name, tmp->element.id);	
    }
    return 0;
}
